#include "mboard.h"
#include "mboard_private.h"
#include "gpio_hw.h"
#include "syscfg_hw.h"
#include "exti_hw.h"
#include "rcc.h"
#include "nvic.h"
#include "mdebug.h"

/**
 * WK_UP:      PA0, 按下高电平
 * KEY0_RIGHT: PE4，按下低电平
 * KEY1_DOWN:  PE3，按下低电平
 * KEY2_LEFT:  PE2，按下低电平
 */
 
 MKeyInfo_t mkeyInfo;

static void mKeyClockInit(void)
{
	/* 使能GPIO、SYSCFG时钟 */
	RCC_EnableAhb1(RCC_CLK_AHB1_GPIOA | RCC_CLK_AHB1_GPIOE);
	RCC_EnableApb2(RCC_CLK_APB2_SYSCFG);
}

static void mKeyGpioInit(void)
{
	uint32_t tmp32;

	/* 输入模式 */
	tmp32 = SOC_GPIOA.MODER;
	tmp32 &= ~GPIO_MODER_MASK(0);
	tmp32 |= GPIO_MODER_IN(0);
	SOC_GPIOA.MODER = tmp32;

	/* 使能下拉 */
	tmp32 = SOC_GPIOA.PUPDR;
	tmp32 &= ~GPIO_PUPDR_MASK(0);
	tmp32 |= GPIO_PUPDR_DOWN(0);
	SOC_GPIOA.PUPDR = tmp32;

	/* 输入模式 */
	tmp32 = SOC_GPIOE.MODER;
	tmp32 &= ~GPIO_MODER_MASK(2);
	tmp32 &= ~GPIO_MODER_MASK(3);
	tmp32 &= ~GPIO_MODER_MASK(4);
	tmp32 |= GPIO_MODER_IN(2);
	tmp32 |= GPIO_MODER_IN(3);
	tmp32 |= GPIO_MODER_IN(4);
	SOC_GPIOE.MODER = tmp32;

	/* 使能上拉 */
	tmp32 = SOC_GPIOE.PUPDR;
	tmp32 &= ~GPIO_PUPDR_MASK(2);
	tmp32 &= ~GPIO_PUPDR_MASK(3);
	tmp32 &= ~GPIO_PUPDR_MASK(4);
	tmp32 |= GPIO_PUPDR_UP(2);
	tmp32 |= GPIO_PUPDR_UP(3);
	tmp32 |= GPIO_PUPDR_UP(4);
	SOC_GPIOE.PUPDR = tmp32;
}

static void mKeyExtiInit(void)
{
	uint32_t tmp32;

	/* EXTI0: PA0 EXTI2: PE2 EXTI3: PE3  */
	tmp32 = SOC_SYSCFG.EXTICR[0];
	tmp32 &= ~SYSCFG_EXTICR0_0_3D(0, SYSCFG_EXTICR_MASK);
	tmp32 &= ~SYSCFG_EXTICR0_0_3D(2, SYSCFG_EXTICR_MASK);
	tmp32 &= ~SYSCFG_EXTICR0_0_3D(3, SYSCFG_EXTICR_MASK);
	tmp32 |= SYSCFG_EXTICR0_0_3D(0, SYSCFG_EXTICR_PA);
	tmp32 |= SYSCFG_EXTICR0_0_3D(2, SYSCFG_EXTICR_PE);
	tmp32 |= SYSCFG_EXTICR0_0_3D(3, SYSCFG_EXTICR_PE);
	SOC_SYSCFG.EXTICR[0] = tmp32;
	/* EXTI4: PE4 */
	tmp32 = SOC_SYSCFG.EXTICR[1];
	tmp32 &= ~SYSCFG_EXTICR1_4_7D(4, SYSCFG_EXTICR_MASK);
	tmp32 |= SYSCFG_EXTICR1_4_7D(4, SYSCFG_EXTICR_PE);
	SOC_SYSCFG.EXTICR[1] = tmp32;

	/* EXTI0/2/3/4上升沿中断使能 */
	tmp32 = SOC_EXTI.RTSR;
	tmp32 &= ~EXTI_RTSR_MASK_0_22D(0);
	tmp32 &= ~EXTI_RTSR_MASK_0_22D(2);
	tmp32 &= ~EXTI_RTSR_MASK_0_22D(3);
	tmp32 &= ~EXTI_RTSR_MASK_0_22D(4);
	tmp32 |= EXTI_RTSR_PERMIT_0_22D(0);
	tmp32 |= EXTI_RTSR_PERMIT_0_22D(2);
	tmp32 |= EXTI_RTSR_PERMIT_0_22D(3);
	tmp32 |= EXTI_RTSR_PERMIT_0_22D(4);
	SOC_EXTI.RTSR = tmp32;

	/* EXTI0/2/3/4下降沿中断使能 */
	tmp32 = SOC_EXTI.FTSR;
	tmp32 &= ~EXTI_FTSR_MASK_0_22D(0);
	tmp32 &= ~EXTI_FTSR_MASK_0_22D(2);
	tmp32 &= ~EXTI_FTSR_MASK_0_22D(3);
	tmp32 &= ~EXTI_FTSR_MASK_0_22D(4);
	tmp32 |= EXTI_FTSR_PERMIT_0_22D(0);
	tmp32 |= EXTI_FTSR_PERMIT_0_22D(2);
	tmp32 |= EXTI_FTSR_PERMIT_0_22D(3);
	tmp32 |= EXTI_FTSR_PERMIT_0_22D(4);
	SOC_EXTI.FTSR = tmp32;

	/* EXTI0/2/3/4中断使能 */
	tmp32 = SOC_EXTI.IMR;
	tmp32 &= ~EXTI_IMR_MASK_0_22D(0);
	tmp32 &= ~EXTI_IMR_MASK_0_22D(2);
	tmp32 &= ~EXTI_IMR_MASK_0_22D(3);
	tmp32 &= ~EXTI_IMR_MASK_0_22D(4);
	tmp32 |= EXTI_IMR_PERMIT_0_22D(0);
	tmp32 |= EXTI_IMR_PERMIT_0_22D(2);
	tmp32 |= EXTI_IMR_PERMIT_0_22D(3);
	tmp32 |= EXTI_IMR_PERMIT_0_22D(4);
	SOC_EXTI.IMR = tmp32;

	/* EXTI0事件使能，EXTI2/3/4事件禁止 */
	tmp32 = SOC_EXTI.EMR;
	tmp32 &= ~EXTI_EMR_MASK_0_22D(0);
	tmp32 &= ~EXTI_EMR_MASK_0_22D(2);
	tmp32 &= ~EXTI_EMR_MASK_0_22D(3);
	tmp32 &= ~EXTI_EMR_MASK_0_22D(4);
	tmp32 |= EXTI_EMR_PERMIT_0_22D(0);
	tmp32 |= EXTI_EMR_FORBID_0_22D(2);
	tmp32 |= EXTI_EMR_FORBID_0_22D(3);
	tmp32 |= EXTI_EMR_FORBID_0_22D(4);
	SOC_EXTI.EMR = tmp32;
}

static void mKeyInterruptInit(void)
{
	NVIC_SetPriority(NVIC_IRQ_EXTI0, NVIC_PRIORITY_LOW,
	                 NVIC_PRIORITY_SUB_NONE);
	NVIC_SetPriority(NVIC_IRQ_EXTI2, NVIC_PRIORITY_LOW,
	                 NVIC_PRIORITY_SUB_NONE);
	NVIC_SetPriority(NVIC_IRQ_EXTI3, NVIC_PRIORITY_LOW,
	                 NVIC_PRIORITY_SUB_NONE);
	NVIC_SetPriority(NVIC_IRQ_EXTI4, NVIC_PRIORITY_LOW,
	                 NVIC_PRIORITY_SUB_NONE);
	NVIC_EnableIrq(NVIC_IRQ_EXTI0);
	NVIC_EnableIrq(NVIC_IRQ_EXTI2);
	NVIC_EnableIrq(NVIC_IRQ_EXTI3);
	NVIC_EnableIrq(NVIC_IRQ_EXTI4);
}

void mKeyInit(void)
{
	mKeyClockInit();
	mKeyGpioInit();
	mKeyExtiInit();
	mKeyInterruptInit();
	/* 设置所有的按键处于弹起的状态 */
	if (MKEY_STATE_RELEASE == 1) {
		mkeyInfo.state.all = 0xF;
	}
}

void mKeyTest(void)
{
	while (1) {
		/* 打印键值 */
		mDebugPrintf("UP:%s DOWN:%s LEFT:%s RIGHT:%s\n",
		             mkeyInfo.state.up    == MKEY_STATE_PRESS ? "按下" : "弹开",
		             mkeyInfo.state.down  == MKEY_STATE_PRESS ? "按下" : "弹开",
		             mkeyInfo.state.left  == MKEY_STATE_PRESS ? "按下" : "弹开",
		             mkeyInfo.state.right == MKEY_STATE_PRESS ? "按下" : "弹开");
		/* 打印按下去的次数 */
		mDebugPrintf("UP:%4u DOWN:%4u LEFT:%4u RIGHT:%4u\n", 
		             (uint32_t)mkeyInfo.count.up,
		             (uint32_t)mkeyInfo.count.down,
		             (uint32_t)mkeyInfo.count.left,
		             (uint32_t)mkeyInfo.count.right);
		mBoardDelayMs(5000);
	}
}
